/*******************************************************************************
 * Copyright (c) 2015 Lincong All rights reserved.
 * This software is the confidential and proprietary information of Lincong.
 * You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with Lincong.
 *  Mail: Lincong <lincong1987@gmail.com>, <lincong@cleverlin.com>
 *    QQ: 159257119
 * Phone: 15925711961
 * $Revision$
 * $Id$
 ******************************************************************************/

/*!
 * The Firebird Javascript Lite Lib.
 *
 * http://www.jplatformx.com/
 *
 * editor lc
 * $Id: firebird-1.0.3.js 16 2014-01-23 10:21:08Z lc $
 *
 * based on baidu tangram 1.5.2.2
 * http://tangram.baidu.com
 */

define(function (require, exports, module) {


	(function (win, doc) {

		/**
		 * 框架主体
		 * @namespace firebird
		 */
		var FB, firebird = FB = firebird || {
				/**
				 * version
				 */
				version: "1.0.4",
				/**
				 * PERIOD
				 */
				PERIOD: ".",
				/**
				 *  DEBUG < INFO < WARN < ERROR
				 */
				debugLevel: "ALL",
				/**
				 * language
				 */
				language: "zh_CN",
				/**
				 * _startTime
				 */
				_startTime: new Date().getTime(),
				/**
				 * noop
				 * an empty function
				 */
				noop: function () {
				}
			};

		/**
		 * 日志
		 * @type {log}
		 */
		firebird.debug = function () {
			if (firebird.debugLevel === "ALL" || firebird.debugLevel === "ERROR" || firebird.debugLevel === "WARN" || firebird.debugLevel === "DEBUG" || firebird.debugLevel === "INFO") {
				var args = Array.prototype.slice.call(arguments);
				if (arguments[0] instanceof Error) {
					var e = arguments[0];
					var stack = firebird.exception.formatStack(e.stack || e.name);
					args = ["\n\nFirebird Stack: [\n\n\t" + stack + "\n]"];
				}
				args.unshift(firebird.date.format(new Date(), "$HH:$mm:$ss.$sss [INFO]: "));
				Function.apply.apply(window.console.log, [window.console, args]);
			}
		};

		firebird.info = firebird.log = firebird.debug;

		/**
		 * warn
		 */
		firebird.warn = function () {
			if (firebird.debugLevel === "ALL" || firebird.debugLevel === "WARN" || firebird.debugLevel === "DEBUG" || firebird.debugLevel === "INFO") {
				var args = Array.prototype.slice.call(arguments);
				if (arguments[0] instanceof Error) {
					var e = arguments[0];
					var stack = firebird.exception.formatStack(e.stack || e.name);
					args = ["\n\nFirebird Stack: [\n\n\t" + stack + "\n]"];
				}
				args.unshift(firebird.date.format(new Date(), "$HH:$mm:$ss.$sss [WARN]: "));
				Function.apply.apply(window.console.trace || window.console.warn, [window.console, args]);
			}
		};
		/**
		 *
		 */
		firebird.error = function () {
			if (firebird.debugLevel === "ALL" || firebird.debugLevel === "ERROR") {
				var args = Array.prototype.slice.call(arguments);
				if (arguments[0] instanceof Error) {
					var e = arguments[0];
					var stack = firebird.exception.formatStack(e.stack || e.name);
					args = ["\n\nFirebird Stack: [\n\n\t" + stack + "\n]"];
				}
				args.unshift(firebird.date.format(new Date(), "$HH:$mm:$ss.$sss [ERROR]: "));
				Function.apply.apply(window.console.error || window.console.trace, [window.console, args]);
			}
		};
		/**
		 *
		 */
		firebird.dir = function () {
			if (firebird.debugLevel === "ALL" || firebird.debugLevel === "ERROR") {
				var args = Array.prototype.slice.call(arguments);
				if (arguments[0] instanceof Error) {
					var e = arguments[0];
					var stack = firebird.exception.formatStack(e.stack || e.name);
					args = ["\n\nFirebird Stack: [\n\n\t" + stack + "\n]"];
				}
				args.unshift(firebird.date.format(new Date(), "$HH:$mm:$ss.$sss [ERROR]: "));
				Function.apply.apply(window.console.trace || window.console.dir, [window.console, args]);
			}
		};
		/**
		 * 命名空间
		 * @returns {*}
		 */
		firebird.namespace = function () {
			var a = arguments, o, i = 0, j, d, arg;
			for (; i < a.length; i++) {
				o = this; //Reset base object per argument or it will get reused from the last
				arg = a[i];
				if (arg.indexOf(this.PERIOD) > -1) { //Skip this if no "." is present
					d = arg.split(this.PERIOD);
					for (j = (d[0] == 'firebird') ? 1 : 0; j < d.length; j++) {
						o[d[j]] = o[d[j]] || {};
						o = o[d[j]];
					}
				} else {
					o[arg] = o[arg] || {};
					o = o[arg]; //Reset base object to the new object so it's returned
				}
			}
			return o;
		};
		/**
		 * 键盘
		 * @type {firebird.keyCode|*|{ALT: number, BACKSPACE: number, CAPS_LOCK: number, COMMA: number, COMMAND: number, COMMAND_LEFT: number, COMMAND_RIGHT: number, CONTROL: number, DELETE: number, DOWN: number, END: number, ENTER: number, ESCAPE: number, HOME: number, INSERT: number, LEFT: number, MENU: number, NUMPAD_ADD: number, NUMPAD_DECIMAL: number, NUMPAD_DIVIDE: number, NUMPAD_ENTER: number, NUMPAD_MULTIPLY: number, NUMPAD_SUBTRACT: number, PAGE_DOWN: number, PAGE_UP: number, PERIOD: number, RIGHT: number, SHIFT: number, SPACE: number, TAB: number, UP: number, F7: number, F12: number, S: number, WINDOWS: number}}
		 */
		firebird.keyCode = firebird.keyCode || {
				ALT: 18,
				BACKSPACE: 8,
				CAPS_LOCK: 20,
				COMMA: 188,
				COMMAND: 91,
				COMMAND_LEFT: 91, // COMMAND
				COMMAND_RIGHT: 93,
				CONTROL: 17,
				DELETE: 46,
				DOWN: 40,
				END: 35,
				ENTER: 13,
				ESCAPE: 27,
				HOME: 36,
				INSERT: 45,
				LEFT: 37,
				MENU: 93, // COMMAND_RIGHT
				NUMPAD_ADD: 107,
				NUMPAD_DECIMAL: 110,
				NUMPAD_DIVIDE: 111,
				NUMPAD_ENTER: 108,
				NUMPAD_MULTIPLY: 106,
				NUMPAD_SUBTRACT: 109,
				PAGE_DOWN: 34,
				PAGE_UP: 33,
				PERIOD: 190,
				RIGHT: 39,
				SHIFT: 16,
				SPACE: 32,
				TAB: 9,
				UP: 38,
				F7: 118,
				F12: 123,
				S: 83,
				WINDOWS: 91 // COMMAND
			};
		/**
		 * firebird.config
		 * @type {firebird.config|*|{path: string}}
		 */
		firebird.config = firebird.config || {
				path: ""
			};

		/**
		 * 操作字符串的方法
		 * @type {firebird.string|*|{}}
		 */
		firebird.string = firebird.string || {};
		/**
		 * 删除目标字符串两端的空白字符
		 * @name firebird.string.trim
		 * @function
		 * @grammar firebird.string.trim(source)
		 * @param {string} source 目标字符串
		 * @remark
		 * 不支持删除单侧空白字符
		 * @shortcut trim
		 * @meta standard
		 *
		 * @returns {string} 删除两端空白字符后的字符串
		 */
		firebird.string.trim = function (source) {
			return String(source).replace(new RegExp("(^[\\s\\t\\xa0\\u3000]+)|([\\u3000\\xa0\\s\\t]+\x24)", "g"), "");
		};
		/**
		 *
		 * @type {Function}
		 */
		firebird.trim = firebird.string.trim;
		/**
		 * 获取目标字符串在gbk编码下的字节长度
		 * @name firebird.string.byteLength
		 * @function
		 * @grammar firebird.string.byteLength(source)
		 * @param {string} source 目标字符串
		 * @remark
		 * 获取字符在gbk编码下的字节长度, 实现原理是认为大于127的就一定是双字节。如果字符超出gbk编码范围, 则这个计算不准确
		 * @meta standard
		 * @see firebird.string.byteSubstr
		 *
		 * @returns {number} 字节长度
		 */
		firebird.string.byteLength = function (source) {
			return String(source).replace(/[^\x00-\xff]/g, "ci").length;
		};
		/**
		 *
		 * @type {Function}
		 */
		firebird.byteLength = firebird.string.byteLength;
		/**
		 * 对目标字符串按gbk编码截取字节长度
		 * @name firebird.string.byteSubstr
		 * @function
		 * @grammar firebird.string.byteSubstr(source, length)
		 * @param {string} source 目标字符串
		 * @param {number} length 需要截取的字节长度
		 * @param {string} [tail] 追加字符串,可选.
		 * @remark
		 * 截取过程中,遇到半个汉字时,向下取整。
		 * @see firebird.string.byteLength
		 *
		 * @returns {string} 字符串截取结果
		 */
		firebird.string.byteSubstr = function (source, length, tail) {
			source = String(source);
			tail = tail || '';
			if (length < 0 || firebird.string.byteLength(source) <= length) {
				return source + tail;
			}

			source = source.substr(0, length).replace(/([^\x00-\xff])/g, "\x241 ")//双字节字符替换成两个
				.substr(0, length)//截取长度
				.replace(/[^\x00-\xff]$/, "")//去掉临界双字节字符
				.replace(/([^\x00-\xff]) /g, "\x241"); //还原
			return source + tail;
		};
		firebird.byteSubstr = firebird.string.byteSubstr;
		/**
		 * 将目标字符串进行驼峰化处理
		 * @name firebird.string.toCamelCase
		 * @function
		 * @grammar firebird.string.toCamelCase(source)
		 * @param {string} source 目标字符串
		 * @remark
		 * 支持单词以“-_”分隔
		 * @meta standard
		 *
		 * @return {string} 驼峰化处理后的字符串
		 */
		firebird.string.toCamel = function (source) {
			//提前判断,提高getStyle等的效率 thanks xianwei
			if (source.indexOf('-') < 0 && source.indexOf('_') < 0) {
				return source;
			}
			return source.replace(/[-_][^-_]/g, function (match) {
				return match.charAt(1).toUpperCase();
			});
		};
		firebird.toCamel = firebird.string.toCamel;


		firebird.extend = function (target, source) {
			for (var p in source) {
				if (source.hasOwnProperty(p)) {
					target[p] = source[p];
				}
			}

			return target;
		};

		/**
		 * 对目标字符串进行html解码
		 * @name firebird.string.decodeHTML
		 * @function
		 * @grammar firebird.string.decodeHTML(source)
		 * @param {string} source 目标字符串
		 * @shortcut decodeHTML
		 * @meta standard
		 * @see firebird.string.encodeHTML
		 *
		 * @returns {string} html解码后的字符串
		 */
		firebird.string.decodeHTML = function (source) {
			var str = String(source)
				.replace(/&quot;/g, '"')
				.replace(/&lt;/g, '<')
				.replace(/&gt;/g, '>')
				.replace(/&amp;/g, "&");
			//处理转义的中文和实体字符
			return str.replace(/&#([\d]+);/g, function (_0, _1) {
				return String.fromCharCode(parseInt(_1, 10));
			});
		};
		firebird.decodeHTML = firebird.string.decodeHTML;
		/**
		 * 对目标字符串进行html编码
		 * @name firebird.string.encodeHTML
		 * @function
		 * @grammar firebird.string.encodeHTML(source)
		 * @param {string} source 目标字符串
		 * @remark
		 * 编码字符有5个:&<>"'
		 * @shortcut encodeHTML
		 * @meta standard
		 * @see firebird.string.decodeHTML
		 *
		 * @returns {string} html编码后的字符串
		 */
		firebird.string.encodeHTML = function (source) {
			return String(source)
				.replace(/&/g, '&amp;')
				.replace(/</g, '&lt;')
				.replace(/>/g, '&gt;')
				.replace(/"/g, "&quot;")
				.replace(/'/g, "&#39;");
		};
		firebird.encodeHTML = firebird.string.encodeHTML;

		/**
		 * firebird.array
		 */
		firebird.array = firebird.array || {};
		/**
		 * 查询数组中指定元素的索引位置
		 * @param {Array} source 需要查询的数组
		 * @param {Any} match 查询项
		 * @param {number} [fromIndex] 查询的起始位索引位置,如果为负数,则从source.length+fromIndex往后开始查找
		 */
		firebird.array.indexOf = function (source, match, fromIndex) {
			var len = source.length,
				iterator = match;
			fromIndex = fromIndex | 0;
			if (fromIndex < 0) {//小于0
				fromIndex = Math.max(0, len + fromIndex);
			}
			for (; fromIndex < len; fromIndex++) {
				if (fromIndex in source && source[fromIndex] === match) {
					return fromIndex;
				}
			}

			return -1;
		};
		/**
		 * 判断一个数组中是否包含给定元素
		 * @param source  需要查询的数组
		 * @param obj   查询项
		 * @returns {boolean}
		 */
		firebird.array.contains = function (source, obj) {
			return (firebird.array.indexOf(source, obj) >= 0);
		};
		/**
		 * 过滤数组中的相同项。如果两个元素相同,会删除后一个元素。
		 * @name firebird.array.unique
		 * @function
		 * @grammar firebird.array.unique(source[, compareFn])
		 * @param {Array} source 需要过滤相同项的数组
		 * @param {Function} [compareFn] 比较两个数组项是否相同的函数,两个数组项作为函数的参数。
		 *
		 * @returns {Array} 过滤后的新数组
		 */
		firebird.array.unique = function (source, compareFn) {
			var len = source.length,
				result = source.slice(0),
				i, datum;
			if ('function' !== typeof compareFn) {
				compareFn = function (item1, item2) {
					return item1 === item2;
				};
			}

			// 从后往前双重循环比较
			// 如果两个元素相同,删除后一个
			while (--len > 0) {
				datum = result[len];
				i = len;
				while (i--) {
					if (compareFn(datum, result[i])) {
						result.splice(len, 1);
						break;
					}
				}
			}

			return result;
		};
		/**
		 * 将两个数组参数合并成一个类似hashMap结构的对象,这个对象使用第一个数组做为key,使用第二个数组做为值,如果第二个参数未指定,则把对象的所有值置为true。
		 * @name firebird.array.hash
		 * @function
		 * @grammar firebird.array.hash(keys[, values])
		 * @param {Array} keys 作为key的数组
		 * @param {Array} [values] 作为value的数组,未指定此参数时,默认值将对象的值都设为true。
		 *
		 * @returns {Object} 合并后的对象{key : value}
		 */
		firebird.array.hash = function (keys, values) {
			var o = {}, vl = values && values.length, i = 0, l = keys.length;
			for (; i < l; i++) {
				o[keys[i]] = (vl && vl > i) ? values[i] : true;
			}
			return o;
		};
		/**
		 * 移除数组中的项
		 * @name firebird.array.remove
		 * @function
		 * @grammar firebird.array.remove(source, match)
		 * @param {Array} source 需要移除项的数组
		 * @param {Any} match 要移除的项
		 * @meta standard
		 * @see firebird.array.removeAt
		 *
		 * @returns {Array} 移除后的数组
		 */
		firebird.array.remove = function (source, match) {
			var len = source.length;
			while (len--) {
				if (len in source && source[len] === match) {
					source.splice(len, 1);
				}
			}
			return source;
		};
		/**
		 * 遍历数组中所有元素,将每一个元素应用方法进行合并,并返回合并后的结果。
		 * @name firebird.array.reduce
		 * @function
		 * @grammar firebird.array.reduce(source, iterator[, initializer])
		 * @param {Array}    source 需要遍历的数组.
		 * @param {Function} iterator 对每个数组元素进行处理的函数,函数接受四个参数:上一次reduce的结果(或初始值),当前元素值,索引值,整个数组.
		 * @param {Object}   [initializer] 合并的初始项,如果没有此参数,默认用数组中的第一个值作为初始值.
		 * @return {Array} reduce后的值.
		 * @see firebird.array.reduce
		 */
		firebird.array.reduce = function (source, iterator, initializer) {
			var i = 0,
				l = source.length,
				found = 0;
			if (arguments.length < 3) {
				//没有initializer的情况,找到第一个可用的值
				for (; i < l; i++) {
					initializer = source[i++];
					found = 1;
					break;
				}
				if (!found) {
					return;
				}
			}

			for (; i < l; i++) {
				if (i in source) {
					initializer = iterator(initializer, source[i], i, source);
				}
			}
			return initializer;
		};
		/**
		 * 遍历数组中所有元素,将每一个元素应用方法进行转换,并返回转换后的新数组。
		 * @name firebird.array.map
		 * @function
		 * @grammar firebird.array.map(source, iterator[, thisObject])
		 * @param {Array}    source   需要遍历的数组.
		 * @param {Function} iterator 对每个数组元素进行处理的函数.
		 * @param {Object} [thisObject] 函数调用时的this指针,如果没有此参数,默认是当前遍历的数组
		 * @return {Array} map后的数组.
		 * @see firebird.array.reduce
		 */
		firebird.array.map = function (source, iterator, thisObject) {
			var results = [],
				i = 0,
				l = source.length;
			for (; i < l; i++) {
				results[i] = iterator.call(thisObject || source, source[i], i);
			}
			return results;
		};

		/**
		 * 操作cookie的方法
		 * @namespace firebird.cookie
		 */
		firebird.cookie = firebird.cookie || {};
		/**
		 * 验证字符串是否合法的cookie键名
		 *
		 * @param {string} key 需要遍历的数组
		 * @meta standard
		 * @return {boolean} 是否合法的cookie键名
		 */
		firebird.cookie._isValidKey = function (key) {
			return (new RegExp("^[^\\x00-\\x20\\x7f\\(\\)<>@,;:\\\\\\\"\\[\\]\\?=\\{\\}\\/\\u0080-\\uffff]+\x24")).test(key);
		};
		/**
		 * 设置cookie的值,不对值进行编码
		 * @name firebird.cookie.setRaw
		 * @function
		 * @grammar firebird.cookie.setRaw(key, value[, options])
		 * @param {string} key 需要设置Cookie的键名
		 * @param {string} value 需要设置Cookie的值
		 * @param {Object} [options] 设置Cookie的其他可选参数
		 * @config {string} [path] cookie路径
		 * @config {Date|number} [expires] cookie过期时间,如果类型是数字的话, 单位是毫秒
		 * @config {string} [domain] cookie域名
		 * @config {string} [secure] cookie是否安全传输
		 * @remark
		 *
		 <b>options参数包括:</b><br>
		 path:cookie路径<br>
		 expires:cookie过期时间,Number型,单位为毫秒。<br>
		 domain:cookie域名<br>
		 secure:cookie是否安全传输

		 * @meta standard
		 * @see firebird.cookie.set,firebird.cookie.getRaw
		 */
		firebird.cookie.setRaw = function (key, value, options) {
			if (!firebird.cookie._isValidKey(key)) {
				return;
			}

			options = options || {};
			// 计算cookie过期时间
			var expires = options.expires;
			if ('number' === typeof options.expires) {
				expires = new Date();
				expires.setTime(expires.getTime() + options.expires);
			}

			document.cookie =
				key + "=" + value
				+ (options.path ? "; path=" + options.path : "")
				+ (expires ? "; expires=" + expires.toGMTString() : "")
				+ (options.domain ? "; domain=" + options.domain : "")
				+ (options.secure ? "; secure" : '');
		};
		/**
		 * 设置cookie的值,用encodeURIComponent进行编码
		 * @name firebird.cookie.set
		 * @function
		 * @grammar firebird.cookie.set(key, value[, options])
		 * @param {string} key 需要设置Cookie的键名
		 * @param {string} value 需要设置Cookie的值
		 * @param {Object} [options] 设置Cookie的其他可选参数
		 * @config {string} [path] cookie路径
		 * @config {Date|number} [expires] cookie过期时间,如果类型是数字的话, 单位是毫秒
		 * @config {string} [domain] cookie域名
		 * @config {string} [secure] cookie是否安全传输
		 * @remark
		 *
		 1. <b>注意:</b>该方法会对cookie值进行encodeURIComponent编码。如果想设置cookie源字符串,请使用setRaw方法。<br><br>
		 2. <b>options参数包括:</b><br>
		 path:cookie路径<br>
		 expires:cookie过期时间,Number型,单位为毫秒。<br>
		 domain:cookie域名<br>
		 secure:cookie是否安全传输

		 * @meta standard
		 * @see firebird.cookie.setRaw,firebird.cookie.get
		 */
		firebird.cookie.set = function (key, value, options) {
			if (value == "") {
				value = "<!-- fb!=!=!fb -->";
			}
			firebird.cookie.setRaw(key, encodeURIComponent(value), options);
		};
		/**
		 * 获取cookie的值,不对值进行解码
		 * @name firebird.cookie.getRaw
		 * @function
		 * @grammar firebird.cookie.getRaw(key)
		 * @param {string} key 需要获取Cookie的键名
		 * @meta standard
		 * @see firebird.cookie.get,firebird.cookie.setRaw
		 *
		 * @returns {string|null} 获取的Cookie值,获取不到时返回null
		 */
		firebird.cookie.getRaw = function (key) {
			if (firebird.cookie._isValidKey(key)) {
				var reg = new RegExp("(^| )" + key + "=([^;]*)(;|\x24)"),
					result = reg.exec(document.cookie);
				if (result) {
					return result[2] || null;
				}
			}

			return null;
		};
		/**
		 * 获取cookie的值,用decodeURIComponent进行解码
		 * @name firebird.cookie.get
		 * @function
		 * @grammar firebird.cookie.get(key)
		 * @param {string} key 需要获取Cookie的键名
		 * @remark
		 * <b>注意:</b>该方法会对cookie值进行decodeURIComponent解码。如果想获得cookie源字符串,请使用getRaw方法。
		 * @meta standard
		 * @see firebird.cookie.getRaw,firebird.cookie.set
		 *
		 * @returns {string|null} cookie的值,获取不到时返回null
		 */
		firebird.cookie.get = function (key) {
			var value = firebird.cookie.getRaw(key);
			if ('string' === typeof value) {
				value = decodeURIComponent(value);
				if (value == "<!-- fb!=!=!fb -->") {
					value = "";
				}
				return value;
			}
			return null;
		};
		firebird.cookie.remove = function (key, options) {
			options = options || {};
			options.expires = new Date(0);
			firebird.cookie.setRaw(key, '', options);
		};

		/**
		 * 操作日期的方法
		 * @namespace firebird.date
		 */
		firebird.date = firebird.date || {};
		/**
		 * 获取当前时间戳
		 * @return 时间戳
		 */
		firebird.date.now = function () {
			return (new Date()).getTime();
		};
		firebird.now = firebird.date.now;
		/**
		 * 将目标字符串转换成日期对象
		 * @name firebird.date.parse
		 * @function
		 * @grammar firebird.date.parse(source)
		 * @param {string} source 目标字符串
		 * @remark
		 *
		 对于目标字符串,下面这些规则决定了 parse 方法能够成功地解析: <br>
		 <ol>
		 <li>短日期可以使用“/”或“-”作为日期分隔符,但是必须用月/日/年的格式来表示,例如"7/20/96"。</li>
		 <li>以 "July 10 1995" 形式表示的长日期中的年、月、日可以按任何顺序排列,年份值可以用 2 位数字表示也可以用 4 位数字表示。如果使用 2 位数字来表示年份,那么该年份必须大于或等于 70。 </li>
		 <li>括号中的任何文本都被视为注释。这些括号可以嵌套使用。 </li>
		 <li>逗号和空格被视为分隔符。允许使用多个分隔符。 </li>
		 <li>月和日的名称必须具有两个或两个以上的字符。如果两个字符所组成的名称不是独一无二的,那么该名称就被解析成最后一个符合条件的月或日。例如,"Ju" 被解释为七月而不是六月。 </li>
		 <li>在所提供的日期中,如果所指定的星期几的值与按照该日期中剩余部分所确定的星期几的值不符合,那么该指定值就会被忽略。例如,尽管 1996 年 11 月 9 日实际上是星期五,"Tuesday November 9 1996" 也还是可以被接受并进行解析的。但是结果 date 对象中包含的是 "Friday November 9 1996"。 </li>
		 <li>JScript 处理所有的标准时区,以及全球标准时间 (UTC) 和格林威治标准时间 (GMT)。</li>
		 <li>小时、分钟、和秒钟之间用冒号分隔,尽管不是这三项都需要指明。"10:"、"10:11"、和 "10:11:12" 都是有效的。 </li>
		 <li>如果使用 24 小时计时的时钟,那么为中午 12 点之后的时间指定 "PM" 是错误的。例如 "23:15 PM" 就是错误的。</li>
		 <li>包含无效日期的字符串是错误的。例如,一个包含有两个年份或两个月份的字符串就是错误的。</li>
		 </ol>

		 *
		 * @returns {Date} 转换后的日期对象
		 */

		firebird.date.parse = function (source) {
			var reg = new RegExp("^\\d+(\\-|\\/)\\d+(\\-|\\/)\\d+\x24");
			if ('string' === typeof source) {
				if (reg.test(source) || isNaN(Date.parse(source))) {
					var d = source.split(/ |T/),
						d1 = d.length > 1
							? d[1].split(/[^\d]/)
							: [0, 0, 0],
						d0 = d[0].split(/[^\d]/);
					return new Date(d0[0] - 0,
						d0[1] - 1,
						d0[2] - 0,
						d1[0] - 0,
						d1[1] - 0,
						d1[2] - 0);
				} else {
					return new Date(source);
				}
			}

			return new Date();
		};
		firebird.date.helpers = {};
		firebird.date.helper = function (name, callback) {
			this.helpers[name] = callback;
		};
		/**
		 * 日期格式化函数
		 * @param {Object} options 参数对象
		 * <br>
		 * options = {
         * date:"",
         * dateObj:"",
         * time:"",
         * format:""
         * }
		 * @example options.format {Object} 格式化模板
		 * yyyy   年份    4位         自1900开始      1900 -
		 * yyy   年份    3位         自1900开始      0 -
		 * M    月份                不自动补0       1 - 12
		 * MM   月份                自动补0         01-12
		 * MMM   月份    英文月份的缩写        Jan to Dec
		 * MMMM   月份    英文月份的全称        January to December
		 * MC    月      中文
		 * MCS   月      中文 短
		 * dd    日期    自动补0
		 * D    日期    不自动补0       01 - 31
		 * HH    小时    01 - 23
		 * H     小时    1 - 23
		 * mm    分钟    00 - 59
		 * m     分钟    1 - 59
		 * ss    秒      00 - 59
		 * s     秒      0 - 59
		 * w     星期    星期天到六的索引    0 - 6
		 * DD    星期    星期天到六英文全称    Sunday - Saturday
		 * D     星期    星期天到六英文缩写    Sun - Sat
		 * DCL   星期    中文 长
		 * DC   星期    中文
		 * DCS   星期    中文 短
		 * 以下内容
		 * firebird.date.format({time: new Date, format: "yyyy|yyy, M|MM|MMM|MMMM|MC|MCS, dd|D, HH|H, mm|m, ss|s, w, DD|D|DCL|DC|DCS"})
		 * 将返回
		 * "2012|112, 7|07|Jul|July|七月|七, 13|Fri, 10|10, 56|56, 27|27, 5, Friday|Fri|星期六|周六|六"
		 */
		firebird.date.format = function (options) {

			// 如果是字符串，直接尝试转换
			if (typeof (options) === "string" || options instanceof Date) {
				var time = this.parse(options);
				options = {
					time: time
				};
				if (arguments.length > 1) {
					options.format = arguments[1];
				}
			}

			var opts = firebird.extend({
					date: null,
					dateObj: null,
					time: null,
					format: "$yyyy-$MM-$dd"
				},
				options);
			if (opts.date === null && opts.dateObj === null && opts.time === null) {
				return "";
			}

			var $date = null;
			if (opts.date !== null) {
				$date = firebird.date.parse(opts.date);
			}

			if (opts.time !== null) {
				$date = new Date();
				$date.setTime(opts.time);
			}

			if (opts.dateObj !== null) {
				$date = new Date();
				if (!opts.dateObj.time) {
					return "";
				}
				$date.setTime(opts.dateObj.time);
			}

			var format = opts.format;
			if (!($date instanceof Date) || firebird.trim(format) === "") {
				return "";
			}

			var $week = ("Sunday Monday Tuesday Wednesday Thursday Friday Saturday").split(" ");
			var $weekShort = ("Sun Mon Tue Wed Thu Fri Sat").split(" ");
			var $weekChineseLong = ("星期日 星期一 星期二 星期三 星期四 星期五 星期六").split(" ");
			var $weekChinese = ("周日 周一 周二 周三 周四 周五 周六").split(" ");
			var $weekChineseShort = ("日 一 二 三 四 五 六").split(" ");
			var $month = ("January February March April May June July August September October November December").split(" ");
			var $monthShort = ("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec").split(" ");
			var $monthChinese = ("一月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一月 十二月").split(" ");
			var $monthChineseShort = ("一 二 三 四 五 六 七 八 九 十 十一 十二").split(" ");
			// 模式
			var $fmt = {
				yyyy: $date.getFullYear().toString(),
				yyy: $date.getYear().toString(),
				//	月份	不自动补0			1 - 12
				M: ($date.getMonth() + 1).toString(),
				//	月份	自动补0				01-12
				MM: firebird.number.pad(($date.getMonth() + 1), 2),
				//	月份	英文月份的缩写		Jan to Dec
				MMM: $monthShort[$date.getMonth()],
				//	月份	英文月份的全称		January to December
				MMMM: $month[$date.getMonth()],
				//	月 中文
				MC: $monthChinese[$date.getMonth()],
				//	月 中文 短
				MCS: $monthChineseShort[$date.getMonth()],
				//	日期	自动补0
				dd: firebird.number.pad($date.getDate(), 2),
				//	日期	不自动补0				01 - 31
				d: $date.getDate().toString(),
				/**
				 * hour    01 - 23
				 */
				HH: firebird.number.pad($date.getHours(), 2),
				/**
				 * hour    1 - 23
				 */
				H: $date.getHours().toString(),
				//	分钟	00 - 59
				mm: firebird.number.pad($date.getMinutes(), 2),
				//	分钟	1 - 59
				m: $date.getMinutes().toString(),
				//	秒		00 - 59
				ss: firebird.number.pad($date.getSeconds(), 2),
				//	秒		0 - 59
				s: $date.getSeconds().toString(),
				//
				sss: $date.getMilliseconds().toString(),
				//	星期	星期天到六的索引	0 - 6
				w: $date.getDay().toString(),
				//	星期	星期天到六英文全称 	Sunday - Saturday
				DD: $week[$date.getDay()],
				//	星期	星期天到六英文缩写 	Sun - Sat
				D: $weekShort[$date.getDay()],
				//	星期 中文 长
				DCL: $weekChineseLong[$date.getDay()],
				//	星期 中文
				DC: $weekChinese[$date.getDay()],
				//	星期 中文 短
				DCS: $weekChineseShort[$date.getDay()]
			};

			/**
			 * ampm
			 */
			$fmt.AMPM = ($fmt.H < 12 ? "上午" : "下午");
			/**
			 * hour 01-12
			 */
			$fmt.hh = ($fmt.HH > 12 ? ($fmt.HH - 12) : $fmt.HH);
			/**
			 * hour 1-12
			 */
			$fmt.h = ($fmt.H > 12 ? ($fmt.H - 12) : $fmt.H);

			// 暴露给helper
			for (var helper in this.helpers) {
				$fmt[helper] = this.helpers($date, $fmt);
			}

			return format.replace(/\$yyyy/g, $fmt.yyyy)
				.replace(/\$yyy/g, $fmt.yyy)
				.replace(/\$MMMM/g, $fmt.MMMM)
				.replace(/\$MMM/g, $fmt.MMM)
				.replace(/\$MM/g, $fmt.MM)
				.replace(/\$MCS/g, $fmt.MCS)
				.replace(/\$MC/g, $fmt.MC)
				.replace(/\$M/g, $fmt.M)
				.replace(/\$dd/g, $fmt.dd)
				.replace(/\$d/g, $fmt.d)
				.replace(/\$HH/g, $fmt.HH)
				.replace(/\$H/g, $fmt.H)
				.replace(/\$hh/g, $fmt.hh)
				.replace(/\$h/g, $fmt.h)
				.replace(/\$mm/g, $fmt.mm)
				.replace(/\$m/g, $fmt.m)
				.replace(/\$sss/g, $fmt.sss)
				.replace(/\$ss/g, $fmt.ss)
				.replace(/\$s/g, $fmt.s)
				.replace(/\$w/g, $fmt.w)
				.replace(/\$DD/g, $fmt.DD)
				.replace(/\$DCL/g, $fmt.DCL)
				.replace(/\$DCS/g, $fmt.DCS)
				.replace(/\$DC/g, $fmt.DC)
				.replace(/\$D/g, $fmt.D)
				.replace(/\$AMPM/g, $fmt.AMPM);
		};


		/**
		 * 操作number的方法
		 * @namespace firebird.number
		 */
		firebird.number = firebird.number || {};
		/**
		 * 为目标数字添加逗号分隔
		 * @name firebird.number.encomma
		 * @function
		 * @grammar firebird.number.encomma(source[, length])
		 * @param {number} source 需要处理的数字
		 * @param {number} [length] 两次逗号之间的数字位数,默认为3位
		 *
		 * @returns {string} 添加逗号分隔后的字符串
		 */
		firebird.number.encomma = function (source, length) {
			if (!length || length < 1) {
				length = 3;
			}

			source = String(source).split(".");
			source[0] = source[0].replace(new RegExp('(\\d)(?=(\\d{' + length + '})+$)', 'ig'), "$1,");
			return source.join(".");
		};
		/**
		 * 去除数字的逗号分隔符
		 * @param {String} source 需要处理的文字
		 */
		firebird.number.decomma = function (source) {
			return source.toString().replace(/\,|\./g, "");
		};
		/**
		 * 对目标数字进行0补齐处理
		 * @name firebird.number.pad
		 * @function
		 * @grammar firebird.number.pad(source, length)
		 * @param {number} source 需要处理的数字
		 * @param {number} length 需要输出的长度
		 *
		 * @returns {string} 对目标数字进行0补齐处理后的结果
		 */
		firebird.number.pad = function (source, length) {
			var pre = "",
				negative = (source < 0),
				string = String(Math.abs(source));
			if (string.length < length) {
				pre = (new Array(length - string.length + 1)).join('0');
			}

			return (negative ? "-" : "") + pre + string;
		};

		/**
		 * 操作url的方法
		 * @namespace firebird.url
		 */
		firebird.url = firebird.url || {};
		/**
		 * 解析目标URL中的参数成json对象
		 * @name firebird.url.parse
		 * @function
		 * @grammar firebird.url.parse(url)
		 * @param {string} url 目标URL
		 * @see firebird.url.jsonToQuery
		 *
		 * @returns {Object} - 解析为结果对象,其中URI编码后的字符不会被解码,'a=%20' ==> {a:'%20'}。
		 */
		firebird.url.parse = function (url) {
			url = url || location.href;
			var query = url.substr(url.lastIndexOf('?') + 1),
				params = query.split('&'),
				len = params.length,
				result = {},
				i = 0,
				key, value, item, param;
			for (; i < len; i++) {
				if (!params[i]) {
					continue;
				}
				param = params[i].split('=');
				key = param[0];
				value = param[1];
				item = result[key];
				if ('undefined' === typeof item) {
					result[key] = value;
				} else if (firebird.lang.isArray(item)) {
					item.push(value);
				} else { // 这里只可能是string了
					result[key] = [item, value];
				}
			}

			return result;
		};
		/**
		 * 根据参数名从目标URL中获取参数值
		 * @name firebird.url.getParameter
		 * @function
		 * @grammar firebird.url.getQueryValue(key, url)
		 * @param {string} key 要获取的参数名
		 * @param {string} url 目标URL
		 * @meta standard
		 * @see firebird.url.jsonToQuery
		 *
		 * @returns {string|null} - 获取的参数值,其中URI编码后的字符不会被解码,获取不到时返回null
		 */
		firebird.url.getParameter = function (key, url) {
			url = url || location.href;
			var reg = new RegExp(
				"(^|&|\\?|#)"
				+ key
				+ "=([^&#]*)(&|\x24|#)",
				"");
			var match = url.match(reg);
			if (match) {
				return match[2];
			}

			return null;
		};
		/**
		 * 对字符串进行%#&+=以及和\s匹配的所有字符进行url转义
		 * @name firebird.url.escape
		 * @function
		 * @grammar firebird.url.escape(source)
		 * @param {string} source 需要转义的字符串.
		 * @return {string} 转义之后的字符串.
		 * @remark
		 * 用于get请求转义。在服务器只接受gbk,并且页面是gbk编码时,可以经过本转义后直接发get请求。
		 *
		 * @return {string} 转义后的字符串
		 */
		firebird.url.escape = function (source) {
			return String(source).replace(/[#%&+=\/\\\ \ \f\r\n\t]/g, function (all) {
				return '%' + (0x100 + all.charCodeAt()).toString(16).substring(1).toUpperCase();
			});
		};

		/**
		 * uuid
		 */
		firebird.S4 = function () {
			return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
		};
		firebird.uuid = function () {
			return (firebird.S4() + firebird.S4() + "-" + firebird.S4() + "-" + firebird.S4() + "-" + firebird.S4() + "-" + firebird.S4() + firebird.S4() + firebird.S4());
		};

		/**
		 * 提供数据缓存功能
		 * @namespace firebird.data
		 */
		firebird.data = firebird.data || {};
		/**
		 * 跨框架数据共享接口
		 * @param {String} key 存储的数据名
		 * @param {Everything} value 将要存储的任意数据
		 * @param {String} area 存储区域 如果key起始为firebird_或top.开头将存入$FIREBIRD_SYS$
		 * @return {Everything} 返回被存储的数据
		 * @example firebird.data.set("dsw", {id:"dsw", name: "daishaowei", sex: "male"});
		 */
		firebird.data.set = function (key, value, area, trigger) {
			var top = window.top,
				area = area || '$FIREBIRD_CACHE$',
				area = key.toString().match(/^firebird\.|^top\./) ? "$FIREBIRD_SYS$" : area,
				cache = top[area] || {};
			top[area] = cache;

			if (trigger) {
				cache["trigger." + key] = trigger;
			}

			return cache[key] = value;
		};
		/**
		 * 跨框架数据共享接口
		 * @param key 存储的数据名
		 * @param area
		 * @param trigger
		 * @returns {*} 返回被查询的数据
		 * @example firebird.data.get("dsw");
		 */
		firebird.data.get = function (key, area) {
			var top = window.top,
				area = area || '$FIREBIRD_CACHE$',
				area = key.toString().match(/^firebird\.|^top\./) ? "$FIREBIRD_SYS$" : area,
				cache = top[area] || {};
			top[area] = cache;

			var trigger = cache["trigger." + key];
			trigger && trigger();

			return cache[key];
		};

		/**
		 * 数据共享删除接口
		 * @param {String} key 删除的数据名
		 * @example firebird.data.remove("dsw");
		 */
		firebird.data.remove = function (key, area) {
			var area = area || '$FIREBIRD_CACHE$',
				area = key.toString().match(/^firebird\.|^top\./) ? "$FIREBIRD_SYS$" : area,
				cache = window.top[area];
			if (cache && cache[key])
				delete cache[key];
		};
		/**
		 * 数据共享清除接口
		 *
		 * @example
		 * step1:
		 * firebird.data.set("key1", "value1");
		 * firebird.data.set("key2", "value2");
		 * firebird.log("key1 is d%, key2 is d%", firebird.data.set("key1"), firebird.data.set("key2"));
		 * step2:
		 * firebird.data.clear();
		 * firebird.log(firebird.log("key1 is d%, key2 is d%", firebird.data.set("key1"), firebird.data.set("key2")););
		 */
		firebird.data.clear = function (area) {
			var area = area || '$FIREBIRD_CACHE$',
				area = area.toString().match(/^firebird\.|^top\./) ? "$FIREBIRD_SYS$" : area;
			window.top[area] = {};
		};

		firebird.data.clearByPrefix = function (prefix, area) {
			var area = area || '$FIREBIRD_CACHE$',
				area = area.toString().match(/^firebird\.|^top\./) ? "$FIREBIRD_SYS$" : area;
			$.each(this.getAll(area), function (key, v) {
				if (key.indexOf(prefix) != -1 || prefix.test(key) == true) {
					firebird.data.remove(key, area);
				}
			});
		};

		/**
		 * 跨框架数据共享接口
		 * @return {Object} 返回被查询的数据
		 * @example firebird.data.getAll();
		 */
		firebird.data.getAll = function (area) {
			var top = window.top,
				area = area || '$FIREBIRD_CACHE$',
				cache = top[area] || {};
			top[area] = cache;
			return cache;
		};

		/**
		 * 混合数据
		 * @param name
		 * @param mix
		 * @param deep
		 * @returns {Object|void|*}
		 * @example
		 * <pre>
		 * firebird.data.set("fruit", {
         *      apple: 1,
         *      orange: 3
         * });
		 *
		 * firebird.data.mix("fruit", {
         *      apple: 2,
         *      banana: 6
         * });
		 *
		 * firebird.object.each(firebird.data.get("fruit"), function(quantity, name){
         *      firebird.info("I have "+quantity+ " " + name);
         * });
		 * // Object {apple: 2, orange: 3, banana: 6}
		 * </pre>
		 */
		firebird.data.mix = function (name, mix, deep) {
			return this.set(name, $.extend(deep || true, this.get(name), mix));
		};
		/**
		 *
		 * @type {Function|*|avalon.mix|mix}
		 */
		firebird.data.extend = firebird.data.mix;

		/**
		 *
		 * @type {firebird.lsdata|*|{}}
		 */
		firebird.lsdata = firebird.lsdata || {};
		/**
		 * 跨框架数据共享接口
		 * @param {String} key 存储的数据名
		 * @param {Everything} value 将要存储的任意数据
		 * @return {Everything} 返回被存储的数据
		 * @example firebird.data.set("dsw", {id:"dsw", name: "daishaowei", sex: "male"});
		 */
		firebird.lsdata.set = function (key, value) {
			this.remove(key);
			localStorage.setItem(key, firebird.json.stringify(value));
			return value;
		};
		/**
		 * 跨框架数据共享接口
		 * @param {String} key 存储的数据名
		 * @return {Everything} 返回被查询的数据
		 * @example firebird.data.get("dsw");
		 */
		firebird.lsdata.get = function (key) {
			var value = localStorage.getItem(key);
			return firebird.json.parse(value);
		};
		/**
		 * 数据共享删除接口
		 * @param {String} key 删除的数据名
		 * @example firebird.data.remove("dsw");
		 */
		firebird.lsdata.remove = function (key) {
			localStorage.removeItem(key);
		};

		firebird.api = firebird.data;

		/**
		 * <h1>国际化处理 在 @cfg alias 内可以使用 @default: 处理默认值</h1>
		 * 默认的语言包定义在 firebird.api.get("languagePack"), 如果要添加相应内容，请使用
		 * firebird.api.mix("languagePack", {
         *      zh_CN: {
         *          server: "服务器",
         *          hi: "你好"
         *      },
         *      zh_TW: {
         *          server: "伺服器",
         *          hi: "安安"
         *      }
         * });
		 * @param {String} alias 别名
		 * @param {Object} pack 语言包
		 * @param {String} locale 地区代码
		 * @returns {*}
		 *
		 * @example
		 * sample1:
		 * <pre>
		 * var pack = {
         *     zh_CN: {
         *          hello: "你好"
         *     },
         *     en_US: {
         *          hello: "hello!"
         *     }
         * };
		 *
		 * alert(firebird.getText("hello", pack)); // 你好
		 * alert(firebird.getText("beef@default:牛肉", pack)); // 牛肉
		 * alert(firebird.getText("hello", pack, "en_US")); // hello!
		 * alert(firebird.getText("hey", pack, "en_US")); // hey
		 * </pre>
		 */
		firebird.getText = function (alias, pack, locale) {
			var alias = alias || "";
			var pack = pack || firebird.api.get("languagePack") || firebird.languagePack || {};
			var locale = locale || firebird.api.get("locale") || firebird.cookie.get("jpx.locale") || firebird.language || "zh_CN";
			var def = "";
			if (/\@default\:/.test(alias) == true) {
				var str = alias.split(/\@default\:/);
				alias = str[0];
				def = str[1];
			}
			if (alias == "") {
				return "";
			}
			return pack[locale] && pack[locale][alias] || (def != "" ? def : alias);
		};

		firebird.info("Thanks for using firebird-" + firebird.version + " javascript library! <lincong1987#gmail.com>");
//console.log("%c  thanks for using firebird javascript library!    ", "border-top: 1px solid #000; border-left: 1px solid #000; border-right: 1px solid #000; width: 500px");
//console.log("%c       ___ _            _     _          _         ", "color:red; border-left: 1px solid #000; border-right: 1px solid #000;");
//console.log("%c      \/ __|_)          | |   (_)        | |        ", "color:orange; border-left: 1px solid #000; border-right: 1px solid #000;");
//console.log("%c     | |__ _  ____ ____| | _  _  ____ _ | |        ", "color:yellow; border-left: 1px solid #000; border-right: 1px solid #000;");
//console.log("%c     |  __) |\/ ___) _  ) || \\| |\/ ___) || |        ", "color:green; border-left: 1px solid #000; border-right: 1px solid #000;");
//console.log("%c     | |  | | |  ( (\/ \/| |_) ) | |  ( (_| |        ", "color:blue; border-left: 1px solid #000; border-right: 1px solid #000;");
//console.log("%c     |_|  |_|_|   \\____)____/|_|_|   \\____|        ", "color:purple; border-left: 1px solid #000; border-right: 1px solid #000;");
//console.log("%c  firebird lib loaded.                             ", "color:green; border-left: 1px solid #000; border-right: 1px solid #000;");
//console.log("%c  @page %d                                         ", "color:green; border-left: 1px solid #000; ", location.href);
//console.log("%c  @urlParamter %O                                  ", "color:green; border-left: 1px solid #000; ", firebird.url.parse());
//console.log("%c  @date %d                        ", "color:green; border-left: 1px solid #000; border-right: 1px solid #000; border-bottom: 1px solid #000;", firebird.date.format({time: firebird.now(), format: "yyyy-MM-dd HH:mm:ss"}));
//console.log("%c                                                   ", " width: 500px");

		/**
		 * 结束
		 */
		firebird.loaded = true;
		window.firebird = firebird;

	})(window, document);

	return window.firebird;
});